package com.skivingcloud.admin.sys.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.skivingcloud.admin.constants.Constant;
import com.skivingcloud.admin.security.SecurityUser;
import com.skivingcloud.admin.sys.entity.*;
import com.skivingcloud.admin.sys.mapper.*;
import com.skivingcloud.admin.sys.service.SysUserService;
import com.skivingcloud.admin.sys.vo.AdminRoute;
import com.skivingcloud.admin.sys.vo.AdminRouteVue;
import com.skivingcloud.admin.sys.vo.AdminRouteVueMeta;
import com.skivingcloud.admin.sys.vo.AdminRouteVueParams;
import com.skivingcloud.common.utils.GenericClass;
import com.skivingcloud.common.utils.PageParameter;
import com.skivingcloud.common.utils.UuidUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *  服务层实现。
 *
 * @author skivingcloud
 * @since 2023-08-28
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    
    @Resource
    private SysMenuMapper sysMenuMapper;
    
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private SysUserStationMapper sysUserStationMapper;
    @Resource
    private SysUserMenuMapper sysUserMenuMapper;
    @Resource
    private SysOrgMapper sysOrgMapper;
    /**
     * 根据用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象
     */
    @Override
    public SysUser loadUserByName(String userName){
        QueryWrapper queryWrapper = QueryWrapper.create().select().where(SysUser::getUsername).eq(userName);
        return this.mapper.selectOneByQuery(queryWrapper);
    }
    
    /**
     * 接口权限
     *
     * @param id 用户id
     * @return 权限列表
     */
    @Override
    public List<String> getUserPermissions(String id){
        QueryColumn mType = QueryMethods.column(SysMenu::getType);
        QueryColumn perms = QueryMethods.column(SysMenu::getPerms);
        QueryWrapper qr = QueryWrapper.create();
        qr.select("m.perms").from(SysMenu.class).as("m")
                .join(SysRoleMenu.class).as("sr").on(
                        wrapper -> wrapper.where(SysMenu::getId).eq(SysRoleMenu::getMenuId)
                ).join(SysUserRole.class).as("su").on(
                        wrapper -> wrapper.where(SysRoleMenu::getRoleId).eq(SysUserRole::getRoleId)
                ).where(SysUserRole::getUserId).eq(id)
                .and(mType.eq(Constant.MenuType.BUTTON.getValue())
                        .or(mType.eq(Constant.MenuType.MENU.getValue())
                                .and(perms.isNotNull(true))));
        QueryWrapper qs = QueryWrapper.create();
        qs.select("m.perms").from(SysMenu.class).as("m")
                .join(SysStationMenu.class).as("sm").on(
                        wrapper -> wrapper.where(SysMenu::getId).eq(SysStationMenu::getMenuId)
                ).join(SysUserStation.class).as("us").on(
                        wrapper -> wrapper.where(SysStationMenu::getStationId).eq(SysUserStation::getStationId)
                ).where(SysUserStation::getUserId).eq(id)
                .and(mType.eq(Constant.MenuType.BUTTON.getValue())
                        .or(mType.eq(Constant.MenuType.MENU.getValue())
                                .and(perms.isNotNull(true))));
        QueryWrapper qu = QueryWrapper.create();
        qu.select("m.perms").from(SysMenu.class).as("m")
                .join(SysUserMenu.class).as("sm").on(
                        wrapper -> wrapper.where(SysMenu::getId).eq(SysUserMenu::getMenuId)
                ).where(SysUserMenu::getUserId).eq(id)
                .and(mType.eq(Constant.MenuType.BUTTON.getValue())
                        .or(mType.eq(Constant.MenuType.MENU.getValue())
                                .and(perms.isNotNull(true))));
        QueryWrapper x = qr.union(qs).union(qu);
        List<Row> list2 = this.mapper.selectRowsByQuery(x);
        return list2.stream().map(m -> m.get("perms").toString()).toList();
    }
    
    /**
     * 检查用户名是否重复
     *
     * @param userName 用户名
     * @param tenantId 租户编号
     * @return 是否存在
     */
    @Override
    public boolean checkUserName(String userName, String tenantId){
        QueryWrapper queryWrapper = QueryWrapper.create().where(SysUser::getUsername).eq(userName);
        List<SysUser> list = this.mapper.selectListByQuery(queryWrapper);
        return !list.isEmpty();
    }
    
    /**
     * 加载用户的菜单
     *
     * @param user     用户
     * @param terminal 终端Constant.TerminalType
     * @return 菜单
     */
    @Override
    public List<AdminRoute> getAllMenuForUser(SecurityUser user, String terminal){
        Map<String, Object> param = new HashMap<>();
        param.put("id", user.getId());
        param.put("terminal", terminal);
        List<SysMenu> list2 = sysMenuMapper.selectUserMenuListBean(param);
        List<AdminRoute> menus = list2.stream().map(m -> {
            AdminRoute adminRoute = new AdminRoute();
            adminRoute.setId(m.getId());
            adminRoute.setParentId(m.getParentId());
            adminRoute.setMenuUrl(m.getUrl());
            adminRoute.setMenuName(m.getName());
            adminRoute.setRouteName(m.getUrl().replace("/", "-"));
            adminRoute.setIcon(m.getIcon());
            adminRoute.setOrderNum(m.getOrderNum());
            SysMenu menuParent =  sysMenuMapper.selectOneById(m.getParentId());
            adminRoute.setParentPath(menuParent == null ? "/" : menuParent.getUrl());
            return adminRoute;
        }).toList();
        List<AdminRoute> routeList = getDashboardRoute();
        routeList.addAll(menus.stream().filter(menu -> menu.getParentId().equals("0"))
                .peek(menu -> menu.setChildren(getChildrenMenus(menu, menus).isEmpty() ? null : getChildrenMenus(menu, menus))).toList());
        
        return routeList;
    }
    
    private List<AdminRoute> getChildrenMenus(AdminRoute menu, List<AdminRoute> menus){
        return menus.stream().filter(m -> m.getParentId().equals(menu.getId()))
                .peek(m -> m.setChildren(getChildrenMenus(m, menus).isEmpty() ? null : getChildrenMenus(m, menus))).toList();
    }
    
    private List<AdminRoute> getDashboardRoute(){
        List<AdminRoute> list = new ArrayList<>();
        AdminRoute adminRoute = new AdminRoute();
        adminRoute.setId("-1");
        adminRoute.setMenuUrl("/index");
        adminRoute.setMenuName("Dashborad");
        adminRoute.setRouteName("dashborad");
        adminRoute.setIcon("icon-dashboard");
        adminRoute.setParentPath("");
        adminRoute.setParentId("0");
        List<AdminRoute> children = getAdminRoutesHome();
        adminRoute.setChildren(children);
        list.add(adminRoute);
        return list;
    }
    
    private static List<AdminRoute> getAdminRoutesHome(){
        List<AdminRoute> children = new ArrayList<>();
        AdminRoute home = new AdminRoute();
        home.setId("-2");
        home.setMenuUrl("/index/home");
        home.setMenuName("主控台");
        home.setRouteName("home");
        home.setParentPath("/index");
        home.setParentId("-1");
        children.add(home);
        AdminRoute workPlace = new AdminRoute();
        workPlace.setId("-3");
        workPlace.setMenuUrl("/index/work-place");
        workPlace.setMenuName("工作台");
        workPlace.setRouteName("workPlace");
        workPlace.setParentPath("/index");
        workPlace.setRootPath(true);
        workPlace.setParentId("-1");
        children.add(workPlace);
        return children;
    }
    
    /**
     * 加载用户的菜单
     *
     * @param user     用户
     * @param terminal 终端Constant.TerminalType
     * @return 菜单
     */
    @Override
    public List<AdminRouteVue> getAllMenuForUserVue(SecurityUser user, String terminal){
        Map<String, Object> param = new HashMap<>();
        param.put("id", user.getId());
        param.put("terminal", terminal);
        List<SysMenu> list2 = sysMenuMapper.selectUserMenuListBean(param);
        List<AdminRouteVue> menus = list2.stream().map(m -> {
            AdminRouteVue adminRoute = new AdminRouteVue();
            adminRoute.setId(m.getId());
            adminRoute.setParentId(m.getParentId());
            adminRoute.setType(m.getType());
            if(m.getUrl().contains("/:")) {
                //路由传参情况的处理
                adminRoute.setPath(m.getUrl().substring(0, m.getUrl().indexOf("/:")) + "/:t/:id/:tagsViewName");
                adminRoute.setName(m.getUrl().substring(0, m.getUrl().indexOf("/:")).replace('/', '-'));
                adminRoute.setComponent(m.getUrl().substring(0, m.getUrl().indexOf("/:")));
                String[] ppp = m.getUrl().substring(m.getUrl().indexOf("/:")).split("/:");
                AdminRouteVueParams params = new AdminRouteVueParams();
                params.setT(ppp[1]);
                params.setId(ppp[2]);
                params.setTagsViewName(ppp[3]);
                adminRoute.setParams(params);
            }else{
                adminRoute.setPath(m.getUrl());
                adminRoute.setName(m.getUrl().replace('/', '-'));
                adminRoute.setComponent(m.getUrl());
            }
            if (m.getRedirect() != null) {
                adminRoute.setRedirect(m.getRedirect());
            }
            AdminRouteVueMeta meta = getAdminRouteVueMeta(m);
            adminRoute.setMeta(meta);
            return adminRoute;
        }).toList();
        List<AdminRouteVue> routeList = getDashboardRouteVue();
        routeList.addAll(menus.stream().filter(menu -> menu.getParentId().equals("0"))
                .peek(menu -> menu.setChildren(getChildRenMenusVue(menu, menus).isEmpty() ? null : getChildRenMenusVue(menu, menus))).toList());
        
        return routeList;
    }

    private static AdminRouteVueMeta getAdminRouteVueMeta(SysMenu m) {
        AdminRouteVueMeta meta = new AdminRouteVueMeta();
        meta.setTitle(m.getName());
        if (Constant.COMMON_YES_OR_NO_NO.equals(m.getSysResource())) {
            meta.setIsLink(m.getUrl());
        }
        meta.setHide(Constant.COMMON_YES_OR_NO_YES.equals(m.getIsHide()));
        meta.setKeepAlive(Constant.COMMON_YES_OR_NO_YES.equals(m.getIsKeepAlive()));
        meta.setAffix(Constant.COMMON_YES_OR_NO_YES.equals(m.getIsAffix()));
        meta.setIframe(Constant.COMMON_YES_OR_NO_NO.equals(m.getSysResource()));
        meta.setRoles(new String[] { "admin" });
        meta.setIcon(m.getIcon());
        return meta;
    }

    private List<AdminRouteVue> getChildRenMenusVue(AdminRouteVue menu, List<AdminRouteVue> menus){
        return menus.stream().filter(m -> m.getParentId().equals(menu.getId()))
                .peek(m -> m.setChildren(getChildRenMenusVue(m, menus).isEmpty() ? null : getChildRenMenusVue(m, menus))).toList();
    }
    
    private List<AdminRouteVue> getDashboardRouteVue(){
        AdminRouteVue adminRouteVue = new AdminRouteVue();
        adminRouteVue.setId("-1");
        adminRouteVue.setParentId("0");
        adminRouteVue.setPath("/home");
        adminRouteVue.setName("home");
        adminRouteVue.setComponent("home/index");
        AdminRouteVueMeta meta = new AdminRouteVueMeta();
        meta.setTitle("首页");
        meta.setIsLink("");
        meta.setHide(false);
        meta.setKeepAlive(true);
        meta.setAffix(true);
        meta.setIframe(false);
        meta.setRoles(new String[] { "admin", "common" });
        meta.setIcon("iconfont icon-shouye");
        adminRouteVue.setMeta(meta);
        List<AdminRouteVue> routeList = new ArrayList<>();
        routeList.add(adminRouteVue);
        return routeList;
    }
    
    /**
     * 分页查询
     *
     * @param parameter 查询参数
     * @return 分页查询结果
     */
    @Override
    public Page<SysUser> queryByPage(PageParameter<SysUser> parameter){
        Page<SysUser> page = new Page<>(parameter.getPage(), parameter.getPageSize());
        SysUser sysUser = parameter.getParam();
        QueryWrapper queryWrapper = QueryWrapper.create().select("u.*", "t.tenant_name", "r.org_name").from(SysUser.class).as("u")
                .leftJoin(SysTenant.class).as("t").on(
                        wrapper -> wrapper.where(SysUser::getTenantId).eq(SysTenant::getId)
                ).leftJoin(SysOrg.class).as("r").on(
                        wrapper -> wrapper.where(SysUser::getOrgId).eq(SysOrg::getId)
                ).where(SysUser::getStatus).ne(Constant.USER_STATUS_DELETED);
        if(sysUser != null){
            if(StringUtils.isNotBlank(sysUser.getUsername())){
                queryWrapper.and(SysUser::getUsername).like(sysUser.getUsername());
            }
            if(StringUtils.isNotBlank(sysUser.getStaffId())){
                queryWrapper.and(SysUser::getStaffId).like(sysUser.getStaffId());
            }
            if(StringUtils.isNotBlank(sysUser.getStaffName())){
                queryWrapper.and(SysUser::getStaffName).like(sysUser.getStaffName());
            }
            if(StringUtils.isNotBlank(sysUser.getOrgName())){
                queryWrapper.and(SysOrg::getOrgName).like(sysUser.getOrgName());
            }
            if(StringUtils.isNotBlank(sysUser.getTenantId())){
                queryWrapper.and(SysUser::getTenantId).eq(sysUser.getTenantId());
            }
            if(StringUtils.isNotBlank(sysUser.getStatus())){
                queryWrapper.and(SysUser::getStatus).eq(sysUser.getStatus());
            }
        }
        queryWrapper.orderBy(SysUser::getOrderNum).asc();
        return this.page(page, queryWrapper);
    }
    
    /**
     * 设置用户角色
     *
     * @param sysUser 用户角色信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setUserRolesByUserId(SysUser sysUser){
        QueryWrapper queryWrapper = QueryWrapper.create().from(SysUserRole.class).where(SysUserRole::getUserId).eq(sysUser.getId());
        sysUserRoleMapper.deleteByQuery(queryWrapper);
        sysUserRoleMapper.insertBatch(sysUser.getRoleIds().stream().map(m -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setId(UuidUtil.get32UUID());
            sysUserRole.setUserId(sysUser.getId());
            sysUserRole.setRoleId(m);
            return sysUserRole;
        }).toList());
    }
    
    /**
     * 设置用户岗位
     *
     * @param sysUser 用户岗位信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setUserStationsByUserId(SysUser sysUser){
        QueryWrapper queryWrapper = QueryWrapper.create().from(SysUserStation.class).where(SysUserStation::getUserId).eq(sysUser.getId());
        sysUserStationMapper.deleteByQuery(queryWrapper);
        sysUserStationMapper.insertBatch(sysUser.getStationIds().stream().map(m -> {
            SysUserStation sysUserStation = new SysUserStation();
            sysUserStation.setId(UuidUtil.get32UUID());
            sysUserStation.setUserId(sysUser.getId());
            sysUserStation.setStationId(m);
            return sysUserStation;
        }).toList());
    }
    
    /**
     * 设置用户资源
     *
     * @param sysUser 用户资源信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setUserMenuByUserId(SysUser sysUser){
        QueryWrapper queryWrapper = QueryWrapper.create().from(SysUserMenu.class).where(SysUserMenu::getUserId).eq(sysUser.getId());
        sysUserMenuMapper.deleteByQuery(queryWrapper);
        sysUserMenuMapper.insertBatch(sysUser.getMenuIds().stream().map(m -> {
            SysUserMenu sysUserMenu = new SysUserMenu();
            sysUserMenu.setId(UuidUtil.get32UUID());
            sysUserMenu.setUserId(sysUser.getId());
            sysUserMenu.setMenuId(m);
            return sysUserMenu;
        }).toList());
    }
    
    /**
     * 获取用户信息，包含机构名称
     *
     * @param id 用户id
     */
    @Override
    public SysUser getUserIncludeById(String id){
        SysUser user = this.getById(id);
        SysOrg org = sysOrgMapper.selectOneById(user.getOrgId());
        user.setOrgName(org.getOrgName());
        return user;
    }
    
    /**
     * 根据岗位ID和用户ID查询用户姓名
     *
     * @param parameter 参数
     * @return 逗号隔开的用户姓名
     */
    @Override
    public String getUserNameByStationIdsAndUserIds(UserQueryParameter parameter){
        if(parameter.getStationIds() == null){
            parameter.setStationIds(new ArrayList<>());
        }
        if(parameter.getUserIds() == null){
            parameter.setUserIds(new ArrayList<>());
        }
        if(parameter.getStationIds().isEmpty() && parameter.getUserIds().isEmpty()){
            return "";
        }
        QueryWrapper queryWrapper = QueryWrapper.create().select("u.*").from(SysUser.class).as("u");
        if(parameter.getStationIds() != null && !parameter.getStationIds().isEmpty()){
            queryWrapper.join(SysUserStation.class).as("t").on(wrapper -> wrapper.where(SysUser::getId).eq(SysUserStation::getUserId)).where(SysUserStation::getStationId).in(parameter.getStationIds());
        }
        queryWrapper.and(SysUser::getId).in(parameter.getUserIds());
        List<SysUser> users = this.mapper.selectListByQuery(queryWrapper);
        return users.stream().map(SysUser::getStaffName).collect(Collectors.joining(","));
    }
    
    /**
     * 获取本租户下用户信息{key，value}
     *
     * @param currentUser 用户
     * @return 用户信息
     */
    @Override
    public List<Map<String, Object>> getAllUserBySelfTenant(SecurityUser currentUser){
        QueryWrapper queryWrapper = QueryWrapper.create().from(SysUser.class).and(SysUser::getTenantId)
                .eq(currentUser.getTenantId()).and(SysUser::getStatus).eq(Constant.USER_STATUS_NORMAL);
        List<SysUser> users = this.mapper.selectListByQuery(queryWrapper);
        return users.stream().map(m -> {
            Map<String, Object> map = new HashMap<>();
            map.put("key", m.getId());
            map.put("value", m.getStaffName());
            return map;
        }).toList();
    }
    
    /**
     * 获取本租户下用户ID
     *
     * @param currentUser 用户
     * @return 用户ID
     */
    @Override
    public List<String> getAllUserIdsBySelfTenant(SecurityUser currentUser){
        QueryWrapper queryWrapper = QueryWrapper.create().from(SysUser.class).and(SysUser::getTenantId)
                .eq(currentUser.getTenantId()).and(SysUser::getStatus).eq(Constant.USER_STATUS_NORMAL);
        List<SysUser> users = this.mapper.selectListByQuery(queryWrapper);
        return users.stream().map(SysUser::getId).toList();
    }
}
